﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.IO;
using System.Reflection;
using System.Threading;

namespace SqliteDriver
{
	/*
		Created just to break up the large driver class. This will take care of all the 
		extended functions that don't necessarily generate Sql driven datasets.
	*/ 
	class ExtensionCommandProcessor
	{
		internal ExtensionCommandProcessor(SqliteDataSource parent)
		{
			this.dataSource = parent;
		}

		/*
			command:		the command to process (duh). Likely to contain parameter values
			object window	preserving the farce that this could work on other than WINFORMS this is a parent object
							to host a dialog.
			connectionConfig param to give the operations access to other connections for eg. copy table and quick diff
			searchText		Filter box text
			out nextCommand A command to execute if this is necessary. See QuickDiff
			Return			true if we've done something to change the grid currently displayed.
		*/
		internal bool ProcessCommand(DbView.Command command, object window, DbViewDriver.IConnectionConfig connectionConfig, String searchText, out DbView.Command nextCommand)
		{
			nextCommand = new DbView.Command(DbView.Commands.Cmnd.Nothing);
			String connectionString = this.dataSource.ConnectionString;
			System.Windows.Forms.Form parent = window as System.Windows.Forms.Form;
			// for sql command api an error message and success flag
			String script = "";
			String execMessage;
			bool isOk = false;

			switch (command.Name)
			{
				case "TEST":
				{
					if (parent != null)
						System.Windows.Forms.MessageBox.Show(parent, "Hi from test");
					return true; // try refresh
				}

				break;
			
				case Cmd.ScriptClass:
				{
					String table = command[DbView.Command.TableParameterName(0)];
					// context for the dialog
					using (ClassBuilderForm  form = new ClassBuilderForm(table, this.dataSource))
					{
						form.ShowDialog(parent);
					}
				}
				break;

				case Cmd.CreateTable:
				{
					// context for the dialog
					Dictionary<string, DbView.FieldInfo[]> schema = SqlTableSchema.MakeDatabaseSchema(connectionString);
					using (CreateTableForm form = new CreateTableForm(schema))
					{
						while (true) // keep displaying the dialog if there is an error
						{
							if (form.ShowDialog(parent) == System.Windows.Forms.DialogResult.OK)
							{
								bool createdOk;
								String result = Helper.GenericExecute(connectionString, form.Script, out createdOk);
								if (createdOk)
									return true;
								else
									System.Windows.Forms.MessageBox.Show(result + "\n" +form.Script, "Create table failed", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
							}
							else 
								return false;
						}
					}
				}
				break;
			}

			//if (command.Cmd == DbView.Commands.Cmnd.Droptable)
			//{
			//    String table = command["TABLE"];
			//    String message = String.Format("Confirm that you want to remove table {0} from the database.", table);
			//    if (this.ConfirmDangerousOperation(parent, "Drop table", message))
			//    {
			//        script = String.Format("DROP TABLE {0};", Helper.SafeTableName(table));
			//        execMessage = Helper.GenericExecute(connectionString, script, out isOk);
			//        if (isOk) return true;
			//        System.Windows.Forms.MessageBox.Show(execMessage + "\n" +script, "Drop table failed", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
			//    }
			//}

			if (command.Cmd == DbView.Commands.Cmnd.Cleartable)
			{
				//String table = command["TABLE"];
				//// TODO: add a confirm dialog
				//if (ConfirmDangerousOperation(parent, "Truncate table", message))
				//{
				//    script = "TRUNCATE TABLE ["+table+"];";
				//    execMessage = Helper.GenericExecute(connectionString, script, out opOk);
				//    if (opOk) return true;
				//    System.Windows.Forms.MessageBox.Show(execMessage + "\n" +script, "truncate table failed", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
				////}

				String table = command["TABLE"];
				String message = String.Format("Confirm that you want to clear all data from table {0}.", table);
				String messageCaption = "Truncate table";
				String failMessage = "Truncate table failed";
				script = String.Format("TRUNCATE TABLE {0};", Helper.SafeTableName(table));
				return this.ExecuteWithFeedback(connectionString, script, failMessage, message, messageCaption, parent);
			}

			//if (command.Cmd == DbView.Commands.Cmnd.RemoveColumn)
			//{
			//    String table = command["TABLE"];
			//    String column = command[DbView.Command.TableParameterName(0)];
			//    String message = String.Format("Confirm that you want to remove column {1} from table {0}.", table, column);
			//    String messageCaption = "Remove column";
			//    String failMessage = "remove column table failed";
			//    script = String.Format("ALTER TABLE {0} DROP COLUMN {1};", Helper.SafeTableName(table), Helper.SafeSqlField(column));

			//    return this.ExecuteWithFeedback(connectionString, script, failMessage, message, messageCaption, parent);
			//}
			//if (command.Cmd == DbView.Commands.Cmnd.AddColumn)
			//{
			//    String table = command["TABLE"];
			//    String column = command[DbView.Command.TableParameterName(0)];
			//    // get 
			//    SqlTableSchema schema = this.dataSource.MakeSchemaFor(table);
			//    DbView.FieldInfo fieldInfo = ModifyColumnForm.NewField();
			//    ModifyColumnForm dialog = new ModifyColumnForm(table, schema, fieldInfo);
			//    while (true)
			//    {
			//        if (dialog.ShowDialog(parent) == System.Windows.Forms.DialogResult.Cancel)
			//            return false;

			//        script = dialog.GenerateScript(false);
				
			//        //String messageCaption = "Add Column";
			//        String failMessage = "Add column failed";
			//        if (this.ExecuteWithFeedback(connectionString, script, failMessage, "", "", parent))
			//            return true; // done ok so leave
			//        // here if execute errored. Redisplay dialog so user can correct or cancel.
			//    }
			//}

		//    if (command.Cmd == DbView.Commands.Cmnd.ChangeColumn)
		//    {
		//        String table = command["TABLE"];
		//        String column = command[DbView.Command.TableParameterName(0)];
		//        // get 
		//        SqlTableSchema schema = this.dataSource.MakeSchemaFor(table);
		//        DbView.FieldInfo fieldInfo = schema[column];

		//        if (!this.CheckColumnIsOkToModify(parent, fieldInfo)) // disallow PKey, index, fkey etc.
		//            return false;

		//        ModifyColumnForm dialog = new ModifyColumnForm(table, schema, fieldInfo);
		//        if (dialog.ShowDialog(parent) == System.Windows.Forms.DialogResult.Cancel)
		//            return false;

		//        script = dialog.GenerateScript(false);
				
		//        String failMessage = "Modify column failed";
		//        // return ExecuteWithFeedback(connectionString, script, failMessage, "", "", parent);
		//        execMessage = Helper.GenericExecute(connectionString, script, out isOk);
		//        if (isOk) return true; // done - hurrah

		//        String altMessage = dialog.AltEffect();
		//        String message = String.Format("Could not modify column without side effects. "+
		//                                       "The side effect is this:\n\n" +
		//                                       "{0}\n\n" +
		//                                       "Would you like to proceed with the change?"
		//                                       , altMessage);
		//        if (System.Windows.Forms.MessageBox.Show(parent, message, "Problem with column change", System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.No)
		//            return false;
		//        // try for alt message
		//        script = dialog.GenerateScript(true);
		//        return this.ExecuteWithFeedback(connectionString, script, failMessage, "", "", parent);
		//    }
		    return false;
		}

		bool ExecuteWithFeedback(String connectionString, String script, String failMessage, String confirmMessage, String confirmTitle, System.Windows.Forms.Form parent)
		{
			bool proceed = true;
			if (confirmMessage.Length > 0)
				if (!this.ConfirmDangerousOperation(parent, confirmTitle, confirmMessage))
					proceed = false;
			if (proceed)
			{
				bool isOk;
				String execMessage = Helper.GenericExecute(connectionString, script, out isOk);
				if (isOk) return true;
				System.Windows.Forms.MessageBox.Show(parent, execMessage + "\n" +script, failMessage, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
			}
			return false;
		}

		bool ConfirmDangerousOperation(System.Windows.Forms.Form parent, String operation, String message)
		{
			System.Windows.Forms.DialogResult answer = System.Windows.Forms.MessageBox.Show(parent, message, operation, System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Warning);
			return (answer == System.Windows.Forms.DialogResult.Yes) ? true : false;
		}

		//private bool CheckColumnIsOkToModify(System.Windows.Forms.Form parent, DbView.FieldInfo fieldInfo)
		//{
		//    String message = "";
		//    if (fieldInfo.IsPKey)
		//        message = "Cannot modify a primary key";
		//    else
		//        if (fieldInfo.IsFKey)
		//            message = "Cannot modify a foreign key column";
		//    else
		//        if (fieldInfo.IsIndexed)
		//            message = "Cannot modify a column in an index";
		//    if (message.Length == 0) return true;

		//    System.Windows.Forms.MessageBox.Show(parent, message, "Cannot modify column", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
		//    return false;
		//}

		SqliteDataSource dataSource;
		/////////////////////////////////////////////////////////////////
		// state
		// use for both copy and compare options.
		String holdCopyTargetDb = "";
		String holdObjectType = "";
	}
}
